/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!				\file		CC_Err.cc
				\date		june 2010
				\author		TNick

				\brief		Implements CC_Err class


	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	Please read ReadMe.txt and Licence.txt in root folder
	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */
#include	<QTextEdit>
#include	<QDebug>
#include	<assert.h>

#include	"CC_App.h"

#include	<gui/var/ErrDlg.h>


/*  INCLUDES    ============================================================ */
//
//
//
//
/*  DEFINITIONS    --------------------------------------------------------- */


/*  DEFINITIONS    ========================================================= */
//
//
//
//
/*  DATA    ---------------------------------------------------------------- */

unsigned				CC_Err::uErrCnt;
QList<CC_Err*>			CC_Err::CacheErr;
CCERR::ETYPE			CC_Err::CacheTypes;
CCERR::ETYPE			CC_Err::AllowedTypes;
CCERR::SHOW_TYPES		CC_Err::ShwTy;
QStringList				CC_Err::CtxNames;
QStringList				CC_Err::ETyNames;
QList<QColor>			CC_Err::ETyColors;


/*  DATA    ================================================================ */
//
//
//
//
/*  FUNCTIONS    ----------------------------------------------------------- */


/* ------------------------------------------------------------------------- */
/* initialization (called before any constructor was ever called)            */
bool					CC_Err::InitErrSys			(void)
{
	QSettings       stgs;
	stgs.beginGroup("Errors");

	uErrCnt = 0;

	/* as the application is starting, we deny all messages; this will
	be a signal to cache the messages and later display them */
	ShwTy = CCERR::SHW_NONE;
	AllowedTypes = CCERR::EEMPTY;
	CacheTypes = CCERR::EEMPTY;

	/* initialize arrays of strings private to error system */
	CtxNames.append(QObject::tr("Generic"));	/* CTX_APP */
	CtxNames.append(QObject::tr("GUI"));		/* CTX_GUI */

	ETyNames.append(QObject::tr("Devel debug"));			/* EDEBUG_000 */
	ETyNames.append(QObject::tr("Low level debug"));		/* EDEBUG_IN */
	ETyNames.append(QObject::tr("Medium level debug"));	/* EDEBUG_M */
	ETyNames.append(QObject::tr("Debug"));				/* EDEBUG */
	ETyNames.append(QObject::tr("Devel warning"));		/* EWAR_IN */
	ETyNames.append(QObject::tr("Warning"));				/* EWAR */
	ETyNames.append(QObject::tr("Devel error"));			/* EERR_IN */
	ETyNames.append(QObject::tr("Error"));				/* EERR */

	ETyColors.append(QColor(
			stgs.value("Col_DevDbg", "#444444").toString()));
	ETyColors.append(QColor(
			stgs.value("Col_LowDbg", "#444444").toString()));
	ETyColors.append(QColor(
			stgs.value("Col_MedDbg", "#444444").toString()));
	ETyColors.append(QColor(
			stgs.value("Col_Dbg", "#444444").toString()));
	ETyColors.append(QColor(
			stgs.value("Col_DevWar", "#0000AA").toString()));
	ETyColors.append(QColor(
			stgs.value("Col_Warning", "#0000AA").toString()));
	ETyColors.append(QColor(
			stgs.value("Col_DevErr", "#FF0000").toString()));
	ETyColors.append(QColor(
			stgs.value("Col_Error", "#FF0000").toString()));

	stgs.endGroup();
	return true;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* termination (errors may still exist in chain)                             */
void					CC_Err::EndErrSys			(void)
{
	QSettings       stgs;
	stgs.beginGroup("Errors");

	/* show any errors that are left in out queue */
	FlushErrSys();

	/* save current settings */
	stgs.setValue("AllowedTypes", AllowedTypes);
	stgs.setValue("ShwTy", ShwTy);

	stgs.setValue("Col_DevDbg", ETyColors[0].name());
	stgs.setValue("Col_LowDbg", ETyColors[0].name());
	stgs.setValue("Col_MedDbg", ETyColors[0].name());
	stgs.setValue("Col_Dbg", ETyColors[0].name());
	stgs.setValue("Col_DevWar", ETyColors[0].name());
	stgs.setValue("Col_Warning", ETyColors[0].name());
	stgs.setValue("Col_DevErr", ETyColors[0].name());
	stgs.setValue("Col_Error", ETyColors[0].name());


	/* no errors are allowed from this point forward */
	ShwTy = CCERR::SHW_NONE;
	AllowedTypes = CCERR::EEMPTY;

	stgs.endGroup();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* the application is entering cruise mode                                  */
void					CC_Err::CruiseErrSys		(void)
{
	QSettings       stgs;
	stgs.beginGroup("Errors");

	AllowedTypes = (CCERR::ETYPE)stgs.value(
			"AllowedTypes", CCERR::EERR | CCERR::EWAR).toInt();
	ShwTy = (CCERR::SHOW_TYPES)stgs.value(
			"ShwTy", CCERR::SHW_OUTORMSG).toInt();


	/* DEBUG */
	AllowedTypes = CCERR::EMAX;
	/* DEBUG */

	FlushErrSys();

	stgs.endGroup();

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* flushes cached messages to an output medium decided by the settings       */
void					CC_Err::FlushErrSys			(void)
{
	/* if there are no errors, there's nothing to do */
	if (CacheErr.count() == 0)
		return;
	if ((CacheTypes & AllowedTypes) == 0)
		return;

#ifdef NO_ADVANCED_GUI
	ErrDlg		dialog(&CacheErr, NULL);
	dialog.exec();
#else
	/* see what kind of display is activated */
	switch	(ShwTy)				{
	case	CCERR::SHW_NONE:	{
					/* we can't show messages at this time */
					return;}
	case	CCERR::SHW_DLG:		{
					/* dialog should manage this */
					ErrDlg		dialog(&CacheErr, g_MW);
					dialog.exec();
					break;}
	case	CCERR::SHW_OUT:		{
					/* use output */
					if (!g_MW->IsOutVisible())
						{
							if (!g_MW->MakeOutVisible())
								{/* could not make it visible */
									ErrDlg		dialog(&CacheErr, g_MW);
									dialog.exec();
									break;
								}
						}
					/* iterate in elements from chain */
					for (int j = 0; j < CacheErr.count(); j++)
						{
							CC_Err*		pCrtE;
							pCrtE = (CC_Err*)CacheErr[j];
							pCrtE->ShowEdit(AllowedTypes, g_MW->tx_out);
						} /* for (int j = 0; j < MultipleErr->count(); j++) */
					break;}
	case	CCERR::SHW_OUTORMSG:{
					/* if output panel is visible, show there; else, in dialog */
					if (g_MW->IsOutVisible())
						{

							/* iterate in elements from chain */
							for (int j = 0; j < CacheErr.count(); j++)
								{
									CC_Err*		pCrtE;
									pCrtE = (CC_Err*)CacheErr[j];

									pCrtE->ShowEdit(AllowedTypes, g_MW->tx_out);
								} /* for (int j = 0; j < MultipleErr->count(); j++) */
						}
					else
						{
							ErrDlg		dialog (&CacheErr, g_MW);
							dialog.exec();
							break;
						}
					break;}
	default:					{
				/* this is an invalid value for ShwTy */
				Q_ASSERT(0);
				ShwTy = CCERR::SHW_OUTORMSG;
				break;}
} /* switch	(ShwTy) */
#endif

	/* we are now entitled to destroy the chain */
	CacheErr.clear();
	CacheTypes = CCERR::EEMPTY;

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* return a new ID                                                           */
unsigned				CC_Err::GetID				(void)
{
	/* this is thread unsafe; however, the problem at hand is not that big
	to consider a blocking mechanism */
	uErrCnt++;
	return uErrCnt;
}
/* ========================================================================= */




/* ------------------------------------------------------------------------- */
/* constructor	                                                             */
CC_Err::CC_Err()
{
	/* at construction time, assign an unique identificator for this
	structure */
	uId = GetID();


}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* destructor	                                                             */
CC_Err::~CC_Err()
{

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* duplicates an error structure internally                                  */
CC_Err*					CC_Err::DupErrI		(void)
{
	CC_Err*	pRet = new CC_Err();
	pRet->uId = uId;
	for (int i = 0; i < Items.count(); i++)
		{
			pRet->Items.append(Items[i]);
#ifdef EM
			qDebug(pRet->Items[i].txt.toAscii());
#endif
		}
	return pRet;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* appends a new message to this instance                                    */
void					CC_Err::Add				(CCERR::ETYPE ty,
												 CCERR::ECTX ctx, QString pErr)
{
	//CCERR::EItem*		it = new CCERR::EItem();
	CCERR::EItem		it;

	/* check input values for consistency */
	Q_ASSERT((ctx >= 0) && (ctx < CCERR::CTX_COUNT));
	Q_ASSERT((ty > CCERR::EEMPTY) && (ty <= CCERR::EMAX));

	/* create a structure of expected type */
	it.ctx = ctx;
	it.ty = ty;
	it.txt = pErr;

	/* and add it to array */
	Items.append(it);
#ifdef EM
	qDebug(Items[Items.count()-1].txt.toAscii());
#endif
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* shows this error                                                          */
void					CC_Err::Show			(void)
{
#ifdef NO_ADVANCED_GUI
	/* dialog should manage this */
	ShowMsgB();
#else
	/* see what kind of display is activated */
	switch	(ShwTy)				{
	case	CCERR::SHW_NONE:	{
					/* we can't show messages at this time */
					CacheErr.append(DupErrI());
					for (int i = 0; i < Items.count(); i++)
						{
							CacheTypes = (CCERR::ETYPE)((unsigned)CacheTypes | (unsigned)Items[i].ty);
						}
					return;}
	case	CCERR::SHW_DLG:		{
					/* dialog should manage this */
					ShowMsgB();
					break;}
	case	CCERR::SHW_OUT:		{
					/* use output */
					if (!g_MW->IsOutVisible())
						{
							if (!g_MW->MakeOutVisible())
								{/* could not make it visible */
									ShowMsgB();
									break;
								}
						}
					ShowEdit(AllowedTypes, g_MW->tx_out);
					break;}
	case	CCERR::SHW_OUTORMSG:{
					OneOrTheOther:
					/* if output panel is visible, show there; else, in dialog */
					if (g_MW->IsOutVisible())
						{
							ShowEdit(AllowedTypes, g_MW->tx_out);
						}
					else
						{
							ShowMsgB();
							break;
						}
					break;}
	default:					{
				/* this is an invalid value for ShwTy */
				Q_ASSERT(0);
				ShwTy = CCERR::SHW_OUTORMSG;
				goto OneOrTheOther;
				break;}
} /* switch	(ShwTy) */
#endif
	Items.clear();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* shows this error / text as a message box                                  */
void					CC_Err::ShowMsgB		(void)
{
	ErrDlg	dialog(this);

	dialog.exec();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* shows this error / text in a RichEdit like widget                         */
void					CC_Err::ShowEdit		(CCERR::ETYPE AlwTypes,
												 QTextEdit* OutTx, bool bColPreserve)
{
	QColor		OrigCol;

	/* the error structure has a list of typed strings */
	if (count() == 0)
		{
			return;
		}

	if (bColPreserve == true)
		{
			OrigCol = OutTx->textColor();
		}

	/* tell the id of this error */
	OutTx->append(QObject::tr("Message id: %1").arg(Get_uId()));

	/* iterate in elements from error list */
	for (int i = 0; i < count(); i++)
		{
			if (Allowed(AlwTypes, i))
				{
					OutTx->setTextColor(ErrTypeColor(Items[i].ty));
					OutTx->append(QObject::tr("\tContext %1, Type %2").arg(Get_Context(i)).arg(Get_ErrType(i)));
					OutTx->append(QString("\t%1").arg(Get_String(i)));
				}
		}
	OutTx->append(QString("\n"));
	if (bColPreserve == true)
		{
			OutTx->setTextColor(OrigCol);
		}

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
/* returns this error / text as a single multiline QString                   */
QString					CC_Err::GetText			(void)
{
	QString		sRet;


	/* tell the id of this error */
	sRet.append(QObject::tr("Error id: %1\n").arg(Get_uId()));

	/* iterate in elements from error list */
	for (int i = 0; i < count(); i++)
		{
			if (Allowed(AllowedTypes, i))
				{
					sRet.append(QObject::tr("\tContext %1, ").arg(Get_Context(i)));
					sRet.append(QObject::tr("Type %1\n\t").arg(Get_ErrType(i)));
					sRet.append(Get_String(i));
					sRet.append("\n");
				}
		}

	return sRet;
}
/* ========================================================================= */


/*  FUNCTIONS    =========================================================== */
//
//
//
//
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
